Ext.define('TS.lib.Util',{
	require:function(classes,callback,ns){
		var c = new Factory.Counter(classes.length,callback);
		for(var i = 0; i<classes.length; i++){
			var x = classes[i];
			x = x.indexOf('#')===0 ? 'TS.view.'+x.substr(1): (ns?ns+'.':'')+x;
			Ext.require(x,c.tik,c);
		}
	},
	requireMinified:function(classes,callback,ns){
		//var c = new Factory.Counter(classes.length,callback);
		if(ns){
			var full_classes=[];
			for(var i = 0; i<classes.length; i++){
				full_classes.push(ns+'.'+classes[i]);
			}
			classes = full_classes;
		}
		
		var url = URL.util.require +'?'+ Ext.Object.toQueryString({
         	classes: Ext.encode(classes),
         	callback:Ext.encode(callback+'')
         });
		
        var s = window.document.createElement('script');
		s.src =url;
		s.type='text/javascript';
		window.document.getElementsByTagName('head')[0].appendChild(s);
        
		//document.write('<script type="text/javascript" src="'+url+'">');
		//Ext.require(url + '&never=mind',function(){alert(1);});
	},
	each:function(array,fn){
		// wywołuje funkcje na kazdym elemencie, 
		// przerywa i zwraca jeśli funkcja zwróci wynik
		var result;
		for (var i=0;i<array.length;i++){
			if((result = fn(array[i])))return result;
		}
	},
	// wyszukuje w arraju obiektu o danej wartosci danego atrybutu (lub wileu atrybutów)
	search:function(array,attr1,val1,attr2,val2,etc){
		var params = [], values = [], _return = [];
		for(var i = 1;i<arguments.length;i+=2){
			params.push(arguments[i]);
			values.push(arguments[i+1]);
		}
		for (i=0;i<array.length;i++){
			var test = true;
			//!this[i] && stack(array);
			
			for(var y=0;y<params.length;y++){ 
				eval('var tmp_param = array[i].'+params[y]);
				if (tmp_param == values[y])	continue;
				else { test=false; break; }
			}
			if(test) _return.push(array[i]);
		}
		return _return.length > 0 ? (_return.length==1? _return[0] : _return) : false;
	},
	attrMatch:function(object,a,exclude){
		!Ext.isArray(exclude) && (exclude = [exclude]);
		
		var f = a.indexOf('%')==0, 
			l = a.lastIndexOf('%')==[a.length-1],		
			a = a.replace(/\%/g,''),
			ret = {};
		
		for(x in object){
			if(
				(
					(f&&l&&(x.indexOf(a)!=-1)) ||
					(l&&x.indexOf(a)==0) ||
					(f&&x.lastIndexOf(a)==(x.length-a.length)) ||
					x==a
				) && !isIn(x,exclude) 
			){
				ret[x] = object[x];
			}
		}
		return ret;
		
	},
	valid:function(){// TODO test : komunikat , [cb] 
		
		if((arguments.length % 2) !=0){
			var cfg  =arguments[arguments.length-1];
			
			if(Ext.isFunction(cfg)){
				cfg = {cb:cfg};
			}
			
			var cb = cfg.cb, mark = 1;
		} else var mark = 0,cb = false,cfg = null;
		
		var prefix = cfg&&cfg.form? cfg.form+'->':'';
		
		for(var i = 0;i<arguments.length-mark;i+=2){
			var stringy = Ext.isString(arguments[i]);// && arguments[i]!= '';
			
			var test =  !stringy ? arguments[i]:
				!Util.fldVal(prefix+arguments[i]);

			if(test){
				//log(stringy,prefix,arguments[i]);
				stringy && Util.fld(prefix+arguments[i]).markInvalid(arguments[i+1]);
				Factory.flyer.bad(arguments[i+1]);
				return false;
			}
		}
		!cb || cb();
		return true;
	},
	
	/**
	 * ACCESS
	 */
	cmp:function(cmp){
		var cs = Ext.ComponentQuery.query(cmp);
		return cs ? cs[0] : null;
	},
	sel:function(aliasOrGrid,index){
		var grid = (Ext.isString(aliasOrGrid))?
			Util.grid(aliasOrGrid): aliasOrGrid; 
		var sm = grid.getSelectionModel();
		if(index || index===0)sm.select(index);
		var sel = sm.getSelection()[0];
		return sel;
	},
	selFirstRow:function(g,clicks){
		!clicks && (clicks = 1);
		
		if(Ext.isString(g)){
			g = Util.grid(g);
		}
		try {
			var sel = Util.sel(g,0);
		} catch (e){// grid jest pusty?
			return null;
		}
		//g.getSelectionModel().selectRange(0);
		switch (clicks){
			case 1:
				g.fireEvent('itemclick', g, sel);
				break;
			default:
				g.fireEvent('itemdblclick', g, sel);		
		}
		return sel;
	},
	grid:function(alias,where){
		return Ext.ComponentQuery.query(alias+'grid' +(where?'['+where+']':''))[0];
	},
	store:function(store){
		return Ext.StoreManager.lookup(store);
	},
	form:function(alias){
		
		return Ext.ComponentQuery.query(alias.indexOf('form')>0? alias : alias+'form')[0];
	},
	win:function(alias){
		return Ext.ComponentQuery.query(alias+'window')[0];
	},
	fld:function(clazz,field){
		!clazz && stack(arguments);
		
		if(!field){
			field = clazz.split('->')[1];
			clazz = clazz.split('->')[0];
		}
		typeof field === 'undefined' && stack(arguments);
		
		var fieldname = field.indexOf('#')!=-1 ? field.replace('#','') : (Ext.isString(clazz)?clazz+'_'+field : field),
			panel = Ext.isString(clazz) ? Util.form(clazz.replace(/_/gi,'')) : clazz
			
		!panel && stack(arguments);
		
		return panel.getForm().findField(fieldname);
	},
	fldVal:function(f1,f2){
		if(Ext.isArray(f1)){ // jeden value wiele pól
			var vals = [];
			for(var i=0;i<f1.length;i++){
				var fld = Util.fld(f1[i]);
				vals.push(typeof f2 !== 'undefined' ? 
					fld.setValue((Ext.isString(f2) && f2.indexOf('->')>0) ? Util.fld(f2).getValue() : f2) : 
					fld.getValue()
				);
			}
			return typeof f2 === 'undefined' ? vals : fld;// TODO pomyslec czy tak jest OK!
		} else {
			var fld = Util.fld(f1);
			!fld && stack(arguments);
			return typeof f2 !== 'undefined' ? 
				fld.setValue((Ext.isString(f2) && f2.indexOf('->')>0) ? Util.fld(f2).getValue() : f2) : 
				fld.getValue();
		}
	},
	fldSel:function(query){
		var fld = Util.fld(query),v = fld.getValue(),row;;
		return v && (row = Util.search(fld.getStore().data.items,'internalId',v))? row.raw : {};
	},
	fldLoad:function(){// zawsze w form
		var fld = this;
		Util.s.load(Util.fld(fld.up('form'),fld.childFld).getStore(),where(fld.name,fld.getValue()));
	},
	btn:function(action, where){
		return Ext.ComponentQuery.query((where || 'viewport')+ ' button[action='+action+']')[0];
	},
	close:function(window){
		var win = Util.win(window);
		!win || win.close();
	},
	del:function(gridview,rowIndex,colIndex,item,e){
		var g = gridview.panel || gridview,
			sm = g.getSelectionModel();
		sm.select(rowIndex);
		var sel = sm.getSelection()[0];
		Factory.confirm('Potwierdzenie', item.deleteConfig.confirm || 'Czy chcesz usunąć obiekt?', function(){		
			Util.request(item.deleteConfig.url,{id:sel.internalId},function(){
				g.getStore().load();
				item.deleteConfig.callback && item.deleteConfig.callback();
				Factory.flyer.good('Obiekt został usunięty');
			});
		});
	},
	request:function(url,params,cb,forceCb){
		Ext.Ajax.request({
			url:url,
			params:params,
			success:function(resp,req){
				var r = Ext.decode(resp.responseText);
				if (r.success){
					cb && cb(r);
					(!cb && r.msg) && Factory.flyer.good(r.msg);// TODO - czy tylko jak niema cb czy zawsze?
				} else {
					Util.error.display(r);
					if(r.window){ // TODO - wskazanie na konkretnego windowa konflików
						Ext.create('TS.lib.Window',{title:r.window.title,width:600,height:300,
							items:[{xtype:'rateconflictgrid',r:r,params:params}]
						});
					}
					forceCb && cb(r);
				}
			},
			failure:function(){
				// jeśli nie uda sie nawiaza komunikacji z serwerem.
				alert("impossible#02 - Util - 72");
			}
		});
	},
	fireButton : function(action,place,now){
		place = place || 'viewport';
		if(now){
			var b = Ext.ComponentQuery.query(place+' button[action='+action+']')[0];
			b.handler(b);
		} else return function(){
			//log(Ext.ComponentQuery.query('viewport button[action=searchclient]'),'a');
			var b = Ext.ComponentQuery.query(place+' button[action='+action+']')[0];
			//log(b,'b');
			b.handler(b);
		};
	},
	closeAllWins: function(){
		Ext.WindowMgr.each(function(w){
			typeof w.close === 'function' && w.close();
		});
	},
	s:{
		load:function(storeId,where,cb){
			var s = Ext.isString(storeId) ? Util.store(storeId) : storeId;
			!s && stack(arguments);
			s.setBaseParam('where',where);
			s.load({
				callback:cb||Ext.emptyFn
			});
		},
		each:function(store1,store2,etc,cfg){
			var args = Array.prototype.slice.call(arguments);
			var cfg = !Ext.isString(args[args.length-1])? args.pop() : {};
			Util.each(args,function(storeId){
				var s = Ext.isString(storeId) ? Util.store(storeId) : storeId;
				cfg.where && s.setBaseParam('where',cfg.where);
				s.load({callback:cfg.cb?cfg.cb:Ext.emptyFn});
			});
		},
		fillEach:function(store1,store2,etc){
			var stores = Array.prototype.slice.call(arguments);
			Util.each(stores,function(store){
				if(Ext.isString(store))store = Util.store(store);
				if(store.data.items.length==0)store.load();
			});
		}
	},
	f:{
		each:function(formName,fields,methods){// another cud of the world
			if(!Ext.isArray(fields))fields = [fields];
			if(!Ext.isArray(methods))methods = [methods];
			Util.each(fields,function(el){
				var fld = Util.fld(formName+'->'+el);
				Util.each(methods,function(meth){
					if(Ext.isString(meth))eval('fld.'+meth+'()');
					else {
						for (x in meth){
							eval('var args = meth.'+x);
							if(!Ext.isArray(args))args=[args];
							eval('var fn = fld.'+x);
							Ext.Function.pass(fn,args,fld)();
						}
					}
				});
			});
		},
		clear:function(ButtonObjectOrFormNameOrFormNameArray,callback){
			var o = ButtonObjectOrFormNameOrFormNameArray;
			
			if(Ext.isString(o)) o = [o];
			
			if(Ext.isArray(o)){
				for(i in o){
					Util.form(o[i]).getForm().reset();
				}
				typeof callback ==='function' && callback();
			} else {
				var f = o.up('form');
				f.getForm().reset();
				typeof o.callback ==='function' && o.callback(f);
				typeof callback ==='function' && callback(f);
			}
		},
		load:function(f,idOrParams,callback){
			if(Ext.isString(f))f = Util.form(f);
			
			Ext.isObject(idOrParams) && Ext.apply(idOrParams,{my_action_type:'load'});
			
			var params = Ext.isNumeric(idOrParams) ? 
				{id:idOrParams,my_action_type:'load'} : idOrParams;
			
			f.getForm().reset();
			
			f.load({
				waitTitle:'Prosze czekać',
				waitMsg: 'Wczytywanie danych...',
				//url:f.url,
				params:params,
				success:function(a,b){
					if(typeof f.onFormLoad === 'function'){
						f.onFormLoad(a,b);
					};
					if(typeof callback === 'function'){
						callback(a,b);
					}
				},
				failure:function(a,b){
					Util.error.display(Ext.decode(b.response.responseText));
				}
			});
			return f;
		},
		del:function(btn){
			
			var me = this, cfg = me.handlerConfig, f = me.up('form'), class_name = f.xtype.split('form')[0],
				idProp = Util.grid(class_name).store.proxy.reader.idProperty;
				
			if ((id = Util.fld(class_name +'->#'+ idProp).getValue()) != ''){
				if(cfg.prepare && (cfg.prepareOutput = cfg.prepare())!==true){
					//eval('var notice = cfg.notices.'+cfg.prepareOutput+';');
					return Factory.flyer.bad(cfg.prepareOutput || 'Nie można usunąć tego obiektu');
				}
				Factory.confirm('Potwierdzenie', cfg.confirm || 'Czy na pewno chcesz usunąć ten obiekt?', 
					function(){
						Util.request(cfg.url,{id:id},function(r){
							f.getForm().reset();
							cfg.cb && cfg.cb(me,r);
							cfg.callback && cfg.callback(me,r);
							Factory.flyer.good(r.msg || 'Obiekt został usunięty.');
						},cfg.forceCb);
					}
				);
			} else {
				Factory.flyer.bad(cfg.notice || 'Obiek nie został jeszcze zapisany');
			}
		},
		save2:function(f,cb){
			var basicForm = f.getForm();
	    	var operate = function(){
	            f.submit({
	            	waitMsg:'Prosze czekać',
	            	waitTitle:'Zapis danych',
	                success:function(_form,_resp){// TODO pomyśle nad psudo_xtype
	                	var clazz = f.xtype ? f.xtype.split('form')[0] : f.pseudo_xtype.split('form')[0],
	                		g = Util.grid(clazz),
	                		idProp = (g) ? 
								g.getStore().proxy.reader.idProperty
		                	:	f.model ? 
		                			Ext.create('TS.model.'+f.model).idProperty
		                		:	clazz+'_id';
	                	if(idf = basicForm.findField(idProp))idf.setValue(b.result.data);
	                	if(cb){
	                		cb(_form,_resp);
	                	}
	                	Factory.flyer.good('Zapisano');// jako handler msg to cos innego
	                },
	                failure:function(form,resp){
	                    Util.error.display(Ext.decode(resp.response.responseText));
	                }
	            });
	    	};
	    	
	    	if(f.methods){
	    		if(f.methods.prepare)me.prepare = f.methods.prepare;
	    		if(f.methods.callback)me.callback = f.methods.callback;
	    	}
	    	
        	if((f.validPass && f.validPass())||basicForm.isValid()){
            	operate();                        
            } else {
                Factory.flyer.bad('Wypełnij poprawnie formularz');
            }
		},
		save:function(btn,msg){// btn moze być buttonem formem lub eventem (jeśli z toola)
			
			switch (btn.$className){
				case 'Ext.button.Button':// button
					var f = btn.up('form'), me = btn;
					break;
				case 'Ext.EventObjectImpl':// tool
					var f = this.up('form'), me = this;
					break;
				default:// form
					Ext.isString(btn)&& (btn = Util.form(btn));// jako nazwa string
				
					if(isIn(btn.alternateClassName[0],'Ext.FormPanel','Ext.form.FormPanel')){
						var f = btn, me = f.methods || {};// TODO przemyślec - był {}, ale potzreba czasem innych danych
					} else {
						Factory.flyer.bad('Nieokreslona sytuacja : Util.f.save : 332');
						return;
					}
					break;
			}
			
			var basicForm = f.getForm();
			
	    	var operate = function(){
	            f.submit({
	            	waitMsg:'Prosze czekać',
	            	waitTitle:'Zapis danych',
	                success:function(a,b,c){// TODO pomyśle nad psudo_xtype
	                	var clazz = f.xtype ? f.xtype.split('form')[0] : f.pseudo_xtype.split('form')[0],
	                		g = Util.grid(clazz),
	                		idProp = (g) ? 
								g.getStore().proxy.reader.idProperty
		                	:	f.model ? 
		                			Ext.create('TS.model.'+f.model).idProperty
		                		:	clazz+'_id';
	                	if(idf = basicForm.findField(idProp))idf.setValue(b.result.data);
	                	
	                	me.callback && me.callback(a,b,c);
	                	Factory.flyer.good(Ext.isString(msg)?msg:'Zapisano');// jako handler msg to cos innego
	                },
	                failure:function(form,resp){
	                    Util.error.display(Ext.decode(resp.response.responseText));
	                }
	            });
	    	}
	    	
	    	if(f.methods){// TODO było f!
	    		if(f.methods.prepare)me.prepare = f.methods.prepare;
	    		if(f.methods.callback)me.callback = f.methods.callback;
	    	}
	    	
	        if(me.prepare? me.prepare(me):true){
	        	if((f.validPass && f.validPass())||basicForm.isValid()){
	            	if(me.confirm)me.confirm(operate);
	            	else operate();                        
	            } else {
	                Factory.flyer.bad('Wypełnij poprawnie formularz');
	            }
	        }
		}
	},
	
	download:function(url,params){
		var form = Ext.getBody().createChild({
	         tag:'form',cls:'x-hidden',
	         action: url,
	         target:'utility_iframe'
	    });
	    if(Ext.isArray(params)){
		    for(var i=0;i<params.length;i++){
		    	var f = params[i];
		    	form.createChild({
		    		tag:'input',type:'hidden',
		    		name:f.n,value:f.v
		    	});
		    }
	    } else {
	    	for(x in params){
	    		form.createChild({
		    		tag:'input',type:'hidden',
		    		name:x,value:params[x]
		    	});
	    	}
	    }
	    form.dom.submit();
	    form.remove();
	},
	
	stack:function(toLog){
		// w ext-all-debug.js nalezy jak sie wywala wstawić:
		//typeof X.y === 'undefined' && stack(X);
		// gdzie X.y ==='undefined' wynika z treści danego błędu.
		
		var callstack = [];
		try {
			i.dont.exist+=0;
		} catch(e) {
			if (e.stack) { //Firefox
				var lines = e.stack.split('\n');
				for (var i=0, len=lines.length; i<len; i++) {
					var match = lines[i].match(/http.*/);
					match && (match[0].indexOf('ext-all-debug.js')== -1) && callstack.push(match[0]);
				}
				callstack.shift();
			}
		}
		log(callstack,toLog);
		console.error('Stack Trace Entry');
	},
	error:{
		display:function(r){
			(!r.reason || r.reason != 'auth_fail') || Factory.flyer.bad('Sesja wygasła lub nie posiadasz odpowiednich uprawnień.')
			
			!r.msg || Factory.flyer.bad(r.msg);
			//(typeof r.data === 'undefined') || My.flyer.bad('Zwrócone dane: '+r.data);
			!r.msgs || Factory.flyer.bad(r.msgs);
			(!r.stack ||typeof r.stack.split !== 'function')|| Factory.flyer.bad(r.stack.split('#').each(function(x){
				needle='application\\controllers';
				if(x.indexOf(needle)>0){return x;}
			}));
			!r.vars || Factory.flyer.bad(r.vars);
		}
	},
	desktopNotify : function(text){
		if(window.webkitNotifications){
			var tweet = {
				title:'Timesheet 2.0',
				text:text || 'Powiadominie systemowe.',
				img:'http://localhost/favicon.ico'
			};
			if (window.webkitNotifications.checkPermission() == 0) {
			  	window.webkitNotifications.createNotification(tweet.img, tweet.title,tweet.text).show();
			} else {
			  window.webkitNotifications.requestPermission();
			}
		}
	}
});window.Util = Ext.create('TS.lib.Util');